home *** CD-ROM | disk | FTP | other *** search
- /* Main program of the Mac interface to Xconq.
- Copyright (C) 1992, 1993, 1994, 1995 Stanley T. Shebs.
-
- Xconq is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 2, or (at your option)
- any later version. See the file COPYING. */
-
- #include "conq.h"
- #include "macconq.h"
- extern int do_key_down_construction(int);
-
- #include <stdarg.h>
- #include <errors.h>
- #include <time.h>
-
- /* The console is a useful debugging hack. When not in use, anything that uses stdout
- should be disabled. */
-
- #ifdef USE_CONSOLE
- #ifdef THINK_C
- #include <console.h>
- #include <Folders.h>
- #else
- #ifndef printf
- printf() {}
- #endif
- #endif
- #endif /* USE_CONSOLE */
-
- #define keyReplyErr 'errn'
-
- /* Function prototypes. */
-
- static pascal OSErr do_ae_open_application(AppleEvent *message, AppleEvent *reply, long refcon);
- static pascal OSErr do_ae_open_documents(AppleEvent *message, AppleEvent *reply, long refcon);
- static pascal OSErr do_ae_print_documents(AppleEvent *message, AppleEvent *reply, long refcon);
- static pascal OSErr do_ae_quit_application(AppleEvent *message, AppleEvent *reply, long refcon);
- static pascal OSErr do_ae_join_game(AppleEvent *message, AppleEvent *reply, long refcon);
-
- static Boolean missed_any_parameters(AppleEvent *message);
-
- /* Global variables. */
-
- /* This is the id of any map modal tool currently in effect. */
-
- int map_modal = 0;
-
- int inbackground;
-
- /* This is the list of maps that we're using. */
-
- struct a_map *maplist;
-
- /* This is the list of lists. */
-
- struct a_list *listlist;
-
- /* This is the list of unit closeups. */
-
- struct a_unit_closeup *unitcloseuplist;
-
- /* This indicates whether the general game resource files was found. */
-
- int foundresourcesfile = FALSE;
-
- /* This flag indicates whether the image etc resource file(s) were found. */
-
- int foundimagesfile = FALSE;
-
- /* The usual width of a scrollbar. */
-
- int sbarwid = 15;
-
- /* True if new maps should show the cell grid. */
-
- int default_draw_grid = TRUE;
-
- /* True if new maps should display names and numbers. */
-
- int default_draw_names = FALSE;
-
- /* (should use these eventually instead) */
-
- int default_draw_unit_names = FALSE;
- int default_draw_unit_numbers = FALSE;
- int default_draw_feature_names = FALSE;
-
- /* True if we're going to use WaitNextEvent. */
-
- int useWNE = FALSE;
-
- /* Rectangle that constrains window dragging. */
-
- Rect dragrect;
-
- /* Rectangle that constrains window resizing. */
-
- Rect sizerect;
-
- /* This is the side that is using this Mac as its display. */
-
- Side *dside = NULL;
-
- /* This points to a spare block of memory that is freed so shutdown code can
- use it (no guarantee that it will tho). */
-
- Handle spare;
-
- /* This is true if savable prefs etc have been saved since being changed. */
- /* (always true for now, nothing being remembered) */
-
- int interfacestatesafe = TRUE;
-
- /* This is true when a single click suffices to move a unit. */
-
- int defaultmoveonclick = TRUE;
-
- int defaultautoselect = TRUE;
-
- int wasingame = TRUE;
-
- int suppresswarnings = FALSE;
-
- int playsounds = TRUE;
-
- /* Set to true if Color QuickDraw is installed. */
-
- int hasColorQD;
-
- /* The range of screen pixel depths that the display has to cope with. */
-
- int minscreendepth = -1;
-
- int maxscreendepth = -1;
-
- /* This is true if AppleEvents are available. */
-
- int hasAppleEvents;
-
- /* This is true if the PPC toolbox is available. */
-
- int hasPPCToolbox;
-
- char *curdatestr = NULL;
-
- int eventloopdone = FALSE;
-
- int inputinvalid = FALSE;
-
- /* True when a won or lost dialog has been put up on the screen already. */
-
- static int told_outcome = FALSE;
-
- /* The main Mac program. */
-
- int
- main()
- {
- /* Do the most basic Macintosh setup. */
- init_toolbox();
- init_cursors();
- init_patterns();
- init_icons();
- init_menus();
- init_rects();
- init_ae();
- #ifdef USE_CONSOLE
- /* Make sure the console window is up before anybody tries to write to it. */
- freopenc(NULL, stdout);
- freopenc(stdout, stderr);
- #endif /* USE_CONSOLE */
- /* Put the Xconq kernel into a known state. */
- clear_game_modules();
- init_data_structures();
- init_library_path(NULL);
- /* Acquire Mac-specific files (preferences and resources). */
- get_files();
- /* A hack to ensure some memory available for error handling. */
- spare = NewHandle(2000);
- /* If no Apple Events, go to the splash screen now, otherwise we'll wait
- for an oapp/odoc/pdoc event to decide what to do. */
- if (!hasAppleEvents) {
- if (splash_dialog() == diSplashQuit)
- return 0;
- }
- /* All essential init done, jump into the main event loop. */
- event_loop();
- /* Will exit here, or perhaps via error. */
- return 0;
- }
-
- /* This is the first dialog that the user sees. It doesn't do much
- besides provide the initial choice into the program proper. */
-
- int
- splash_dialog()
- {
- switch (do_splash_box()) {
- case diSplashNew:
- new_game_dialog();
- break;
- case diSplashOpen:
- open_game_dialog();
- break;
- case diSplashConnect:
- connect_game_dialog();
- break;
- case diSplashQuit:
- return diSplashQuit;
- }
- return -1;
- }
-
- /* (just a place holder for now) */
-
- void
- connect_game_dialog()
- {
- LocationNameRec foo;
- PortInfoRec bar;
-
- PPCBrowser("\pChoose an Xconq game to join:",
- "\pXconq", 0, &foo, &bar, NULL, "\p?");
- }
-
- /* Do the usual Mac setup calls. */
-
- void
- init_toolbox()
- {
- SysEnvRec se;
-
- MaxApplZone();
-
- InitGraf(&QD(thePort));
- InitFonts();
- FlushEvents(everyEvent, 0);
- InitWindows();
- InitMenus();
- TEInit();
- InitDialogs(NULL);
- InitCursor();
-
- SysEnvirons(2, &se);
- hasColorQD = se.hasColorQD;
- DGprintf("%s Color QuickDraw\n", (hasColorQD ? "Using" : "Not using"));
- recalc_depths();
- }
-
- /* Look at all the devices and compute the range of screen depths. */
-
- void
- recalc_depths()
- {
- int depth, oldmin = minscreendepth, oldmax = maxscreendepth;
- GDHandle gdev;
-
- if (hasColorQD) {
- gdev = GetDeviceList();
- minscreendepth = maxscreendepth = (*((*gdev)->gdPMap))->pixelSize;
- while ((gdev = GetNextDevice(gdev)) != nil) {
- depth = (*((*gdev)->gdPMap))->pixelSize;
- if (depth < minscreendepth) minscreendepth = depth;
- if (depth > maxscreendepth) maxscreendepth = depth;
- }
- } else {
- minscreendepth = maxscreendepth = 1;
- }
- if (minscreendepth != oldmin || maxscreendepth != oldmax) {
- DGprintf("Screen depths range from %d to %d\n", minscreendepth, maxscreendepth);
- }
- }
-
- /* Set up the generic dragging and sizing rects. */
-
- void
- init_rects()
- {
- RgnHandle screenrgn;
-
- screenrgn = GetGrayRgn();
- dragrect = (*screenrgn)->rgnBBox;
- SetRect(&sizerect, 50, 50, (*screenrgn)->rgnBBox.right, (*screenrgn)->rgnBBox.bottom);
- }
-
- /* Basic Apple Event handling. */
-
- void
- init_ae()
- {
- OSErr err;
- long rslt;
-
- hasPPCToolbox = (Gestalt(gestaltPPCToolboxAttr, &rslt) ? false : (rslt != 0));
- hasAppleEvents = (Gestalt(gestaltAppleEventsAttr, &rslt) ? false : (rslt != 0));
-
- if (hasAppleEvents) {
- err = AEInstallEventHandler(kCoreEventClass, kAEOpenApplication,
- (ProcPtr) do_ae_open_application, 0L, false);
- if (err) {
- /* Alert(rErrorAlert, nil); */
- beep();
- return;
- }
- err = AEInstallEventHandler(kCoreEventClass, kAEOpenDocuments,
- (ProcPtr) do_ae_open_documents, 0L, false);
- if (err) {
- /* Alert(rErrorAlert, nil); */
- beep();
- return;
- }
- err = AEInstallEventHandler(kCoreEventClass, kAEPrintDocuments,
- (ProcPtr) do_ae_print_documents, 0L, false);
- if (err) {
- /* Alert(rErrorAlert, nil); */
- beep();
- return;
- }
- err = AEInstallEventHandler(kCoreEventClass, kAEQuitApplication,
- (ProcPtr) do_ae_quit_application, 0L, false);
- if (err) {
- /* Alert(rErrorAlert, nil); */
- beep();
- return;
- }
- err = AEInstallEventHandler('xcnq', 'join',
- (ProcPtr) do_ae_join_game, 0L, false);
- if (err) {
- /* Alert(rErrorAlert, nil); */
- beep();
- return;
- }
- }
- }
-
- short prefs_refnum = -1;
-
- /* Open and/or load any files that we might need, such as preferences
- and resources. */
-
- void
- get_files()
- {
- Str255 filename;
- extern short initialvrefnum;
-
- /* Capture the current vrefnum. */
- GetVol(NULL, &initialvrefnum);
- /* Load up any preferences. */
- get_preferences();
- /* Look for and open game library resource files. */
- foundresourcesfile = FALSE;
- GetIndString(filename, sFilenames, siResources);
- if (OpenResFile(filename) != -1) {
- foundresourcesfile = TRUE;
- }
- foundimagesfile = FALSE;
- GetIndString(filename, sFilenames, siImages);
- if (OpenResFile(filename) != -1) {
- foundimagesfile = TRUE;
- }
- GetIndString(filename, sFilenames, siSounds);
- if (OpenResFile(filename) != -1) {
- /* (need to do anything special if sounds not found??) */
- }
- /* Note that we don't complain yet if the resource/image files are missing,
- since we don't yet know whether we actually need anything from them.
- (Images etc might be built into app or game module, for instance.) */
- }
-
- int
- open_preferences()
- {
- short vref;
- long dirid;
- OSErr err;
- Str255 filename;
-
- GetIndString(filename, sFilenames, siPreferences);
- /* (should do a gestalt check first) */
- err = FindFolder(kOnSystemDisk, kPreferencesFolderType, kDontCreateFolder,
- &vref, &dirid);
- if (err != noErr) {
- SysEnvRec se;
-
- err = SysEnvirons(1, &se);
- if (err == noErr) {
- vref = se.sysVRefNum;
- } else {
- vref = 0;
- }
- dirid = 0;
- }
- err = HCreate(vref, dirid, filename, XconqSignature, 'pref');
- if (err == dupFNErr) err = noErr;
- if (err == noErr) {
- /* Ensure that the resource fork exists. */
- HCreateResFile(vref, dirid, filename);
- prefs_refnum = HOpenResFile(vref, dirid, filename, fsRdWrPerm);
- if (prefs_refnum == -1)
- err = -1;
- if (ResError())
- err = ResError();
- }
- return err;
- }
-
- void
- close_preferences()
- {
- CloseResFile(prefs_refnum);
- prefs_refnum = -1;
- }
-
- void
- get_preferences()
- {
- int startlineno = 0, endlineno = 0;
- char *name;
- Obj *uispec, *rest, *bdg;
- OSErr err;
- Handle prefs;
- extern int checkpointinterval;
-
- err = open_preferences();
- if (err == noErr) {
- UseResFile(prefs_refnum);
- prefs = GetResource('XCpf', 128);
- if (prefs != nil) {
- uispec = read_form_from_string(copy_string(*prefs), &startlineno, &endlineno);
- if (consp(uispec)
- && symbolp(car(uispec))
- && strcmp(c_string(car(uispec)), "mac") == 0) {
- for (rest = cdr(uispec); rest != lispnil; rest = cdr(rest)) {
- bdg = car(rest);
- if (symbolp(car(bdg))) {
- name = c_string(car(bdg));
- if (strcmp(name, "sound") == 0) {
- playsounds = c_number(cadr(bdg));
- } else if (strcmp(name, "default-draw-grid") == 0) {
- default_draw_grid = c_number(cadr(bdg));
- } else if (strcmp(name, "default-draw-names") == 0) {
- default_draw_names = c_number(cadr(bdg));
- } else if (strcmp(name, "checkpoint-interval") == 0) {
- checkpointinterval = c_number(cadr(bdg));
- } else {
- }
- }
- }
- }
- }
- close_preferences();
- }
- }
-
- void
- save_preferences()
- {
- int cur_refnum;
- char prefbuf[300];
- Obj *uispec, *bdg;
- OSErr err;
- Handle oldprefs, prefs;
- extern int checkpointinterval;
-
- err = open_preferences();
- if (err == noErr) {
- uispec = lispnil;
- bdg = cons(intern_symbol("checkpoint-interval"), cons(new_number(checkpointinterval), lispnil));
- uispec = cons(bdg, uispec);
- bdg = cons(intern_symbol("default-draw-grid"), cons(new_number(default_draw_grid), lispnil));
- uispec = cons(bdg, uispec);
- bdg = cons(intern_symbol("default-draw-names"), cons(new_number(default_draw_names), lispnil));
- uispec = cons(bdg, uispec);
- bdg = cons(intern_symbol("sound"), cons(new_number(playsounds), lispnil));
- uispec = cons(bdg, uispec);
- uispec = cons(intern_symbol("mac"), uispec);
- sprintlisp(prefbuf, uispec);
- /* Copy the string into a handle that will be used for the resource. */
- prefs = NewHandle(strlen(prefbuf) + 1);
- HLock(prefs);
- strcpy(*prefs, prefbuf);
- HUnlock(prefs);
- cur_refnum = CurResFile();
- UseResFile(prefs_refnum);
- oldprefs = GetResource('XCpf', 128);
- if (oldprefs != nil) {
- RmveResource(oldprefs);
- UpdateResFile(prefs_refnum);
- }
- AddResource(prefs, 'XCpf', 128, "\pXconq Preferences");
- close_preferences();
- UseResFile(cur_refnum);
- }
- }
-
- /* Since Mac programs effectively take over the entire machine, we depend on
- this event loop to handle everything that might come along. */
-
- void
- event_loop()
- {
- int done = FALSE;
- Boolean gotevent;
- Point mouse;
- EventRecord event;
- RgnHandle cursorRgn;
- short itemhit;
- DialogPtr dialog;
- extern WindowPtr playersetupwin;
-
- /* Figure out if the WaitNextEvent Trap is available. */
- useWNE = (NGetTrapAddress(0x60, ToolTrap) != NGetTrapAddress(0x9f, ToolTrap));
- /* Pass WNE an empty region the 1st time thru. */
- cursorRgn = NewRgn();
- /* Loop (almost) forever. */
- while (!eventloopdone) {
- /* Use WaitNextEvent if it is available, otherwise GetNextEvent. */
- if (useWNE) {
- get_global_mouse(&mouse);
- adjust_cursor(mouse, cursorRgn);
- gotevent = WaitNextEvent(everyEvent, &event, 0L, cursorRgn);
- } else {
- SystemTask();
- gotevent = GetNextEvent(everyEvent, &event);
- }
- /* First decide if the event is for a dialog or is just any old event. */
- if (FrontWindow() != nil && IsDialogEvent(&event)) {
- /* Handle all the modeless dialogs here. */
- if (playersetupwin != nil && playersetupwin == FrontWindow())
- handle_player_setup_event(&event);
- if (DialogSelect(&event, &dialog, &itemhit)) {
- if (dialog == instructionswin) {
- hit_instructions_dialog(dialog, itemhit, &event);
- }
- if (dialog == playersetupwin) {
- mouse = event.where;
- SetPort(playersetupwin);
- GlobalToLocal(&mouse);
- if (hit_player_setup_dialog(itemhit, mouse))
- launch_game_2();
- }
- /* If this was something like a key or click event, but wasn't handled
- by the dialog, we're done and can go wait for the next event.
- Otherwise, for null events, fall through to the usual handling. */
- if (gotevent)
- continue;
- }
- }
- if (gotevent) {
- /* Make sure we have the right cursor before handling the event. */
- adjust_cursor(event.where, cursorRgn);
- handle_event(&event);
- } else if (!beforestart && !endofgame) {
- /* On null events, give the kernel a chance to run something. */
- /* DON'T automatically go to a watch cursor, since run_game often
- returns very quickly. Instead, long-running subroutines should
- call back to put a watch cursor up. */
- run_game(1);
- maybe_select_next_unit();
- /* If the game ended, force various changes in interaction. */
- if (endofgame)
- set_end_of_game_interaction_modes();
- }
- }
- }
-
- void
- get_global_mouse(Point *mouse)
- {
- EventRecord evt;
-
- OSEventAvail(0, &evt);
- *mouse = evt.where;
- }
-
- void
- set_end_of_game_interaction_modes()
- {
- Map *map;
-
- for_all_maps(map) {
- map->moveonclick = map->autoselect = FALSE;
- force_update(map->window);
- }
- }
-
- Point lastmouse;
-
- char mouseoverbuf[100];
-
- /* Change the cursor to reflect the context. */
-
- void
- adjust_cursor(Point mouse, RgnHandle region)
- {
- int x, y, approxdir = 1, usual = TRUE;
- Unit *unit = NULL;
- extern char *mouseover;
- Map *map;
- CursPtr adjust_designer_cursor();
- GrafPtr oldport;
-
- map = map_from_window(FrontWindow());
- if (map != NULL) {
- GetPort(&oldport);
- SetPort(map->window);
- GlobalToLocal(&mouse);
- if (mouse.h > conwid && mouse.h < map->window->portRect.right - sbarwid
- && mouse.v > map->toph && mouse.v < map->window->portRect.bottom - sbarwid) {
- if (map_modal != NO_MODAL) {
- switch (map_modal) {
- case ZOOM_MODAL:
- SetCursor(*opencrosscursor);
- break;
- case FIRE_MODAL:
- case FIRE_INTO_MODAL:
- SetCursor(*firecursor);
- break;
- default:
- run_error("unknown modal tool %d", map_modal);
- break;
- }
- usual = FALSE;
- #ifdef DESIGNERS
- } else if (dside->designer && tooltype != notool) {
- SetCursor(adjust_designer_cursor(mouse, region)); usual = FALSE;
- #endif DESIGNERS
- } else if (map->moveonclick) {
- if (map->numselections == 1
- && (unit = map->selections[0]) != NULL) {
- /* Calculate the approx dir to here from selected unit. */
- m_nearest_cell(map, mouse.h, mouse.v, &x, &y);
- /* Note that we allow x,y here to be outside the world. */
- if (mobile(unit->type)
- && (approxdir = approx_dir(x - unit->x, y - unit->y)) >= 0) {
- SetCursor(*(movecursors[approxdir])); usual = FALSE;
- } else {
- SetCursor(*nomovecursor); usual = FALSE;
- }
- } else if (map->numselections > 1) {
- SetCursor(*allmovecursor); usual = FALSE;
- } else {
- /* (this is a little confusing here if no units are selected, since
- will just be arrow cursor) */
- }
- }
- /* This isn't really "cursor adjustment", but this is the right place
- to do it - change the topline of the map to indicate what the cursor
- is over. */
- if (map->toph > 0 && !EqualPt(mouse, lastmouse)) {
- oneliner(map, mouse.h, mouse.v);
- if (strcmp(tmpbuf, mouseoverbuf) != 0) {
- strcpy(mouseoverbuf, tmpbuf);
- mouseover = mouseoverbuf;
- draw_top_line(map);
- }
- lastmouse = mouse;
- }
- } else {
- if (map->toph > 0) {
- if (mouseover != NULL) {
- mouseover = NULL;
- draw_top_line(map);
- }
- }
- }
- SetPort(oldport);
- }
-
- if (endofgame || (!beforestart && dside && !dside->ingame)) {
- SetCursor(*grayarrowcursor);
- return;
- }
- /* If we got here and no cursor has been set already, go with the basic arrow. */
- if (usual)
- SetCursor(&QD(arrow));
- }
-
- /* Decipher an event. */
-
- int
- handle_event(EventRecord *event)
- {
- short part, err, rslt = 0;
- WindowPtr win;
- char key;
- Point pnt;
-
- switch (event->what) {
- case mouseDown:
- /* See if the click happened in a special part of the screen. */
- part = FindWindow(event->where, &win);
- switch (part) {
- case inMenuBar:
- adjust_menus();
- do_menu_command(MenuSelect(event->where));
- break;
- case inSysWindow:
- SystemClick(event, win);
- break;
- case inContent:
- if (win != FrontWindow()) {
- /* Bring the clicked-on window to the front. */
- SelectWindow(win);
- /* Fix the menu to match the new front window. */
- adjust_menus();
- /* We always want to discard the event now, since clicks in a
- windows are often irreversible actions. */
- } else {
- /* Mouse clicks in the front window do something useful. */
- do_mouse_down(win, event);
- }
- break;
- case inDrag:
- /* Standard drag behavior, no tricks necessary. */
- DragWindow(win, event->where, &dragrect);
- break;
- case inGrow:
- grow_window(win, event->where);
- break;
- case inZoomIn:
- case inZoomOut:
- zoom_window(win, event->where, part);
- break;
- case inGoAway:
- close_window(win);
- break;
- }
- break;
- case keyDown:
- case autoKey:
- key = event->message & charCodeMask;
- /* Check for menukey equivalents. */
- if (event->modifiers & cmdKey) {
- if (event->what == keyDown) {
- adjust_menus();
- do_menu_command(MenuKey(key));
- }
- } else {
- if (event->what == keyDown) {
- int handled = FALSE;
-
- /* Random keypress, interpret it. */
- if (FrontWindow() == constructionwin)
- handled = do_key_down_construction(key);
- if (!handled)
- do_keyboard_command(key);
- }
- }
- break;
- case activateEvt:
- activate_window((WindowPtr) event->message, event->modifiers & activeFlag);
- break;
- case updateEvt:
- update_window((WindowPtr) event->message);
- break;
- case diskEvt:
- /* Call DIBadMount in response to a diskEvt, so that the user can format
- a floppy. (from DTS Sample) */
- if (HiWord(event->message) != noErr) {
- SetPt(&pnt, 50, 50);
- err = DIBadMount(pnt, event->message);
- }
- break;
- case app4Evt:
- /* Grab only a single byte. */
- switch ((event->message >> 24) & 0xFF) {
- case 0xfa:
- break;
- case 1:
- inbackground = !(event->message & 1);
- activate_window(FrontWindow(), !inbackground);
- break;
- }
- break;
- case kHighLevelEvent:
- AEProcessAppleEvent(event);
- break;
- case nullEvent:
- rslt = 1;
- break;
- default:
- break;
- }
- #ifdef DEBUGGING
- /* This just forces output into the file. */
- update_debugging();
- #endif
- return rslt;
- }
-
- /* Handle window growing by mindlessly tracking via GrowWindow,
- then passing the chosen size to specific window resize handlers
- or else doing the generic resize. */
-
- void
- grow_window(WindowPtr win, Point where)
- {
- long winsize;
- short winh, winv;
- GrafPtr oldport;
-
- if ((winsize = GrowWindow(win, where, &sizerect)) != 0) {
- GetPort(&oldport);
- SetPort(win);
- winh = LoWord(winsize); winv = HiWord(winsize);
- if (map_from_window(win)) {
- grow_map(map_from_window(win), winh, winv);
- } else if (list_from_window(win)) {
- grow_list(list_from_window(win), winh, winv);
- } else if (win == historywin) {
- grow_history(winh, winv);
- } else if (win == constructionwin) {
- grow_construction(winh, winv);
- } else if (win == helpwin) {
- grow_help(winh, winv);
- }
- SetPort(oldport);
- }
- }
-
- void
- zoom_window(WindowPtr win, Point where, int part)
- {
- GrafPtr oldport;
-
- if (TrackBox(win, where, part)) {
- GetPort(&oldport);
- /* The window must be the current port. (ZoomWindow bug) */
- SetPort(win);
- if (map_from_window(win)) {
- zoom_map(map_from_window(win), part);
- } else if (list_from_window(win)) {
- zoom_list(list_from_window(win), part);
- } else if (win == constructionwin) {
- zoom_construction(part);
- } else if (win == historywin) {
- zoom_history(part);
- } else if (win == helpwin) {
- zoom_help(part);
- } else {
- /* Generic window zooming. */
- EraseRect(&win->portRect);
- ZoomWindow(win, part, true);
- InvalRect(&win->portRect);
- }
- SetPort(oldport);
- }
- }
-
- void
- close_window(WindowPtr win)
- {
- if (is_da_window(win)) {
- CloseDeskAcc(((WindowPeek) win)->windowKind);
- } else if (is_app_window(win)) {
- /* Remove from the windows menu (OK to call even if window not in menu). */
- remove_window_menu_item(win);
- /* Do special activities for some window subtypes. */
- if (map_from_window(win)) {
- destroy_map(map_from_window(win));
- } else if (list_from_window(win)) {
- destroy_list(list_from_window(win));
- } else if (unit_closeup_from_window(win)) {
- destroy_unit_closeup(unit_closeup_from_window(win));
- #ifdef DESIGNERS
- } else if (win == designwin) {
- /* Closing the design palette implies we're done designing. */
- disable_designing();
- #endif /* DESIGNERS */
- }
- /* Remove the window from our sight, will provoke update events. */
- HideWindow(win);
- /* At least for now, don't actually dispose of the window. */
- }
- }
-
- /* This just dispatches to the appropriate window handler. */
-
- void
- do_mouse_down(WindowPtr window, EventRecord *event)
- {
- Point mouse;
- Map *map;
- List *list;
- UnitCloseup *unitcloseup;
-
- if (is_app_window(window)) {
- SetPort(window);
- mouse = event->where;
- GlobalToLocal(&mouse);
- /* Locate the interface object that this is on. */
- if ((map = map_from_window(window)) != NULL) {
- do_mouse_down_map(map, mouse, event->modifiers);
- } else if ((list = list_from_window(window)) != NULL) {
- do_mouse_down_list(list, mouse, event->modifiers);
- } else if ((unitcloseup = unit_closeup_from_window(window)) != NULL) {
- do_mouse_down_unit_closeup(unitcloseup, mouse, event->modifiers);
- } else if (window == gamewin) {
- do_mouse_down_game(mouse, event->modifiers);
- } else if (window == historywin) {
- do_mouse_down_history(mouse, event->modifiers);
- } else if (window == constructionwin) {
- do_mouse_down_construction(mouse, event->modifiers);
- } else if (window == helpwin) {
- do_mouse_down_help(mouse, event->modifiers);
- #ifdef DESIGNERS
- } else if (window == designwin) {
- do_mouse_down_design(mouse, event->modifiers);
- #endif /* DESIGNERS */
- }
- } else {
- /* ??? */
- }
- }
-
- /* Bringing a window to the front may entail messing with the menu. */
-
- void
- activate_window(WindowPtr win, int activate)
- {
- Map *map;
- List *list;
-
- if (win == nil) return;
- if (activate) {
- /* It's convenient to make the activated window also be the current GrafPort. */
- SetPort(win);
- }
- adjust_menus();
- if ((map = map_from_window(win)) != NULL) {
- activate_map(map, activate);
- } else if ((list = list_from_window(win)) != NULL) {
- activate_list(list, activate);
- } else if (win == constructionwin) {
- activate_construction(activate);
- } else if (win == helpwin) {
- activate_help(activate);
- } else {
- DGprintf("%sactivating random window\n", (activate ? "" : "de"));
- }
- }
-
- /* Update a given window. This is the main routine that causes drawing into
- all the different kinds of windows. */
-
- void
- update_window(WindowPtr win)
- {
- int controls = TRUE, growbox = FALSE;
- GrafPtr oldport;
- Map *map;
- List *list;
- UnitCloseup *unitcloseup;
-
- /* Set the updating window to be the current grafport. */
- GetPort(&oldport);
- SetPort(win);
- recalc_depths();
- BeginUpdate(win);
- if ((map = map_from_window(win)) != NULL) {
- draw_map(map);
- growbox = TRUE;
- } else if ((list = list_from_window(win)) != NULL) {
- draw_list(list);
- growbox = TRUE;
- } else if ((unitcloseup = unit_closeup_from_window(win)) != NULL) {
- draw_unit_closeup(unitcloseup);
- } else if (win == gamewin) {
- draw_game();
- controls = FALSE;
- } else if (win == historywin) {
- draw_history();
- growbox = TRUE;
- } else if (win == constructionwin) {
- draw_construction();
- growbox = TRUE;
- } else if (win == helpwin) {
- draw_help();
- growbox = TRUE;
- #ifdef DESIGNERS
- } else if (win == designwin) {
- draw_design_window();
- controls = FALSE;
- #endif /* DESIGNERS */
- } else {
- controls = FALSE;
- }
- if (controls) {
- UpdateControls(win, win->visRgn);
- }
- if (growbox) {
- DrawGrowIcon(win);
- }
- EndUpdate(win);
- SetPort(oldport);
- }
-
- static int last_tick_count = 0;
-
- void
- maybe_select_next_unit()
- {
- Unit *unit;
- Map *map;
-
- if ((!beforestart && !endofgame)
- && (map = map_from_window(FrontWindow())) != NULL
- && map->autoselect) {
- /* Hunt around for a reasonable "next unit" to select. */
- /* Scroll over to the current unit if appropriate. */
- if (map->curunit != NULL
- && in_play(map->curunit)
- && (map->curunit->act
- && map->curunit->act->acp > 0) /* should be "above min"? */
- && (map->curunit->plan
- && !map->curunit->plan->asleep
- && !map->curunit->plan->reserve
- && !map->curunit->plan->delayed)
- && map->scrolltocurunit
- ) {
- scroll_to_unit(map, map->curunit);
- map->scrolltocurunit = FALSE;
- goto blink;
- }
- unit = autonext_unit_inbox(dside, map->curunit, map->vp);
- if (unit
- && unit->plan
- && !unit->plan->asleep
- && !unit->plan->reserve
- && !unit->plan->delayed
- && unit->plan->waitingfortasks
- ) {
- map->curunit = unit;
- select_exactly_one_unit(map, map->curunit);
- goto blink;
- }
- /* Look for the next unit. */
- unit = find_next_awake_mover(dside, map->curunit);
- if (unit
- && unit->plan
- && !unit->plan->asleep
- && !unit->plan->reserve
- && !unit->plan->delayed
- && unit->plan->waitingfortasks
- ) {
- map->curunit = unit;
- select_exactly_one_unit(map, map->curunit);
- goto blink;
- }
- /* Start over from beginning of list. */
- unit = find_next_awake_mover(dside, NULL);
- if (unit
- && unit->plan
- && !unit->plan->asleep
- && !unit->plan->reserve
- && !unit->plan->delayed
- && unit->plan->waitingfortasks
- ) {
- map->curunit = unit;
- select_exactly_one_unit(map, map->curunit);
- goto blink;
- }
- blink:
- if (map->curunit != NULL) {
- int tick_count;
-
- tick_count = TickCount();
- if (tick_count - last_tick_count >= 10) {
- last_tick_count = tick_count;
- animation_pattern_state = (animation_pattern_state + 1) % 8;
- draw_selection_animation(map, map->curunit);
- }
- }
- }
- }
-
- /* Used to check for any unread required parameters. Returns true if we
- missed at least one. */
-
- Boolean
- missed_any_parameters(AppleEvent *message)
- {
- OSErr err;
- DescType ignoredActualType;
- AEKeyword missedKeyword;
- Size ignoredActualSize;
- EventRecord event;
-
- err = AEGetAttributePtr(message, keyMissedKeywordAttr, typeKeyword, &ignoredActualType,
- (Ptr) &missedKeyword, sizeof(missedKeyword), &ignoredActualSize);
- /* No error means that we found some unused parameters. */
- if (err == noErr) {
- event.message = *(long *) &ignoredActualType;
- event.where = *(Point *) &missedKeyword;
- err = errAEEventNotHandled;
- }
- /* errAEDescNotFound means that there are no more parameters. If we get
- an error code other than that, flag it. */
- return (err != errAEDescNotFound);
- }
-
- static pascal OSErr
- do_ae_open_application(AppleEvent *message, AppleEvent *reply, long refcon)
- {
- #pragma unused (message, refcon)
- OSErr err;
-
- if (splash_dialog() == diSplashQuit) {
- /* Set the global that lets the whole program exit. */
- eventloopdone = TRUE;
- }
- AEPutParamPtr(reply, keyReplyErr, typeShortInteger, (Ptr) &err, sizeof(short));
- return err;
- }
-
- /* Called when we receive an AppleEvent with an ID of "kAEOpenDocuments".
- This routine gets the direct parameter, parses it up into little FSSpecs,
- and opens the first indicated file. It also shows the technique to be used in
- determining if you are doing everything the AppleEvent record is telling
- you. Parameters can be divided up into two groups: required and optional.
- Before executing an event, you must make sure that you've read all the
- required events. This is done by making an "any more?" call to the
- AppleEvent manager. */
-
- static pascal OSErr
- do_ae_open_documents(AppleEvent *message, AppleEvent *reply, long refcon)
- {
- #pragma unused (refcon)
-
- OSErr err, err2;
- AEDesc theDesc;
- FSSpec fsspec;
- short loop;
- long numFilesToOpen;
- AEKeyword ignoredKeyWord;
- DescType ignoredType;
- Size ignoredSize;
-
- theDesc.dataHandle = nil;
-
- err = AEGetParamDesc(message, keyDirectObject, typeAEList, &theDesc);
- if (err)
- return err;
- if (!missed_any_parameters(message)) {
- /* Got all the parameters we need. Now, go through the direct object,
- see what type it is, and parse it up. */
- err = AECountItems(&theDesc, &numFilesToOpen);
- if (!err) {
- /* We have numFilesToOpen that need opening, as either a window
- or to be printed. Go to it... */
- for (loop = 1; ((loop <= numFilesToOpen) && (!err)); ++loop) {
- err = AEGetNthPtr(&theDesc, loop, typeFSS, &ignoredKeyWord, &ignoredType,
- (Ptr) &fsspec, sizeof(fsspec), &ignoredSize);
- if (err)
- break;
- if (open_game_from_fsspec(&fsspec))
- break;
- }
- }
- }
- err2 = AEDisposeDesc(&theDesc);
- err = (err ? err : err2);
- AEPutParamPtr(reply, keyReplyErr, typeShortInteger, (Ptr) &err, sizeof(short));
- return err;
- }
-
- static pascal OSErr
- do_ae_print_documents(AppleEvent *message, AppleEvent *reply, long refcon)
- {
- OSErr err;
-
- AEPutParamPtr(reply, keyReplyErr, typeShortInteger, (Ptr) &err, sizeof(short));
- return err;
- }
-
- static pascal OSErr
- do_ae_quit_application(AppleEvent *message, AppleEvent *reply, long refcon)
- {
- OSErr err = noErr;
-
- /* Set the global that lets the whole program exit. */
- eventloopdone = TRUE;
- AEPutParamPtr(reply, keyReplyErr, typeShortInteger, (Ptr) &err, sizeof(short));
- return noErr;
- }
-
- static pascal OSErr
- do_ae_join_game(AppleEvent *message, AppleEvent *reply, long refcon)
- {
- #pragma unused (message, refcon)
- OSErr err = noErr;
-
- if (playersetupwin != nil) {
- add_remote_player(NULL);
- } else {
- beep();
- beep();
- beep();
- }
- return err;
- }
-
- /* A warning just gets displayed, no other action is taken. */
-
- void
- low_init_warning(char *str)
- {
- Str255 buf;
-
- if (suppresswarnings) return;
- /* Cursor may be weird from loading, reset it. */
- SetCursor(&QD(arrow));
- c2p(str, buf);
- ParamText(buf, "\p", "\p", "\p");
- switch (CautionAlert(aInitWarning, nil)) {
- case 1:
- /* Just keep going, hope that warning was a false alarm. */
- if (0 /* option key or some such */) {
- suppresswarnings = TRUE;
- }
- break;
- case 2:
- /* It would be better to undo everything and blast back to initial choices,
- but that would be pretty hard to implement, and should be a rare occurrence
- anyway. */
- ExitToShell();
- break;
- }
- }
-
- /* An init error is not necessarily fatal, but we still have to start over. */
-
- void
- low_init_error(char *str)
- {
- Str255 buf;
-
- /* Cursor may be weird from loading, reset it. */
- SetCursor(&QD(arrow));
- c2p(str, buf);
- ParamText(buf, "\p", "\p", "\p");
- StopAlert(aInitError, nil);
- /* This is a bad time to choke, no way to recover. Fortunately,
- it's not a big loss, since there's no game yet to lose,
- and so we can just exit directly. */
- ExitToShell();
- }
-
- /* Runtime warnings are for when it's important to bug the players,
- but doesn't necessarily mean imminent danger of a crash. */
-
- void
- low_run_warning(char *str)
- {
- Str255 buf;
-
- if (suppresswarnings) return;
- /* If we're not actually in the game yet, make an init warning instead. */
- if (beforestart) {
- low_init_warning(str);
- return;
- }
- c2p(str, buf);
- ParamText(buf, "\p", "\p", "\p");
- switch (CautionAlert(aRunWarning, nil)) {
- case 1:
- if (0 /* option key?? */) {
- suppresswarnings = TRUE;
- }
- break;
- case 2:
- save_the_game(TRUE, TRUE);
- ExitToShell();
- break;
- case 3:
- /* Just blast out of here. */
- ExitToShell();
- break;
- }
- }
-
- /* An run error is fatal, but allow an emergency save, might be able to salvage. */
-
- void
- low_run_error(char *str)
- {
- Str255 buf;
-
- /* If we're not actually in the game yet, make an init error instead. */
- if (beforestart) {
- low_init_error(str);
- return;
- }
- /* Make some space available, in case this is a memory exhaustion error. */
- if (spare != nil) {
- DisposHandle(spare);
- spare = nil;
- }
- c2p(str, buf);
- ParamText(buf, "\p", "\p", "\p");
- switch (StopAlert(aRunError, nil)) {
- case 1:
- break;
- case 2:
- save_the_game(TRUE, TRUE);
- break;
- }
- /* We're outta here - just ahead of scrambled heaps and dangling ptrs! */
- ExitToShell();
- }
-
- /* This is true when a side has a display that may be safely written to. */
-
- int
- active_display(Side *side)
- {
- return (side && side->ui && side->ui->active);
- }
-
- /* The Mac never has any display buffers to flush. */
-
- void
- flush_display_buffers(Side *side)
- {
- }
-
- /* Detect types of windows. */
-
- int
- is_da_window(WindowPtr win)
- {
- return (win != nil && ((WindowPeek) win)->windowKind < 0);
- }
-
- int
- is_app_window(WindowPtr win)
- {
- return (win != nil && ((WindowPeek) win)->windowKind >= 0);
- }
-
- void
- notify(Side *side, char *format, ...)
- {
- va_list ap;
- char tmpnbuf[BUFSIZE];
-
- if (active_display(side)) {
- va_start(ap, format);
- vsprintf(tmpnbuf, format, ap);
- va_end(ap);
- /* Always capitalize first char of notice. */
- if (islower(tmpnbuf[0])) tmpnbuf[0] = toupper(tmpnbuf[0]);
- /* (should do something with the result!) */
- }
- }
-
- /* Kernel callback to update info about the given side. */
-
- void
- update_side_display(Side *side, Side *side2, int rightnow)
- {
- GrafPtr oldport;
- extern int mayseeall;
-
- if (active_display(side) && side2 != NULL) {
- GetPort(&oldport);
- if (gamewin != nil && ((WindowPeek) gamewin)->visible) {
- SetPort(gamewin);
- draw_side_status(side2);
- }
- SetPort(oldport);
- if (side2 == dside && !side->ingame && side->status == 0 && wasingame) {
- /* (should be able to quit from here?) */
- CautionAlert(aOutOfGame, nil);
- wasingame = FALSE;
- mayseeall = TRUE;
- }
- }
- }
-
- /* Kernel callback to show the current turn. */
-
- void
- update_turn_display(Side *side, int rightnow)
- {
- GrafPtr oldport;
- Map *map;
- extern char *curseasonname;
-
- if (active_display(side)) {
- strcpy(curdatestr + 1, absolute_date_string(g_turn()));
- if (curseasonname != NULL) {
- strcat(curdatestr + 1, " (");
- strcat(curdatestr + 1, curseasonname);
- strcat(curdatestr + 1, ")");
- }
- curdatestr[0] = strlen(curdatestr + 1);
- GetPort(&oldport);
- if (gamewin != nil && ((WindowPeek) gamewin)->visible) {
- SetPort(gamewin);
- draw_game_date();
- }
- for_all_maps(map) {
- if (map->toph > 0) {
- SetPort(map->window);
- draw_top_line(map);
- }
- }
- SetPort(oldport);
- }
- }
-
- /* Callback that gets run once after all turn setup is done but before any movement. */
-
- void
- update_action_display(Side *side, int rightnow)
- {
- GrafPtr oldport;
- Map *map;
- List *list;
- UnitCloseup *unitcloseup;
-
- if (active_display(side)) {
- GetPort(&oldport);
- for_all_maps(map) {
- draw_selections(map);
- if (map->autoselect) {
- unselect_all(map);
- map->curunit = NULL;
- }
- }
- for_all_lists(list) {
- reorganize_list(list);
- }
- for_all_unit_closeups(unitcloseup) {
- force_update(unitcloseup->window);
- }
- SetPort(oldport);
- }
- }
-
- void
- update_action_result_display(Side *side, Unit *unit, int rslt, int rightnow)
- {
- Action *action;
-
- if (active_display(side)) {
- DGprintf("%s %s result is %s\n",
- unit_desig(unit),
- action_desig((unit->act ? &(unit->act->nextaction) : NULL)),
- hevtdefns[rslt].name);
- /* (should handle errors specially) */
- action = (unit->act ? &(unit->act->nextaction) : NULL);
- if (action == NULL) return;
- switch (action->type) {
- case A_CREATE_IN:
- case A_CREATE_AT:
- case A_BUILD:
- if (rslt == A_ANY_DONE) {
- update_construction_type_list();
- }
- break;
- }
- }
- }
-
- void
- update_event_display(Side *side, HistEvent *hevt, int rightnow)
- {
- int data0;
- extern int mayseeall;
-
- data0 = hevt->data[0];
- if (active_display(side)) {
- switch (hevt->type) {
- case H_SIDE_LOST:
- if (side->id == data0) {
- lost_game_dialog();
- told_outcome = TRUE;
- mayseeall = TRUE;
- }
- break;
- case H_SIDE_WON:
- if (side->id == data0) {
- won_game_dialog();
- told_outcome = TRUE;
- mayseeall = TRUE;
- }
- break;
- case H_GAME_ENDED:
- /* Don't display the generic game-end dialog if we already
- got a lost or won dialog. */
- if (!told_outcome)
- game_over_dialog();
- mayseeall = TRUE;
- break;
- default:
- /* No special display for these types of events. */
- break;
- }
- /* Also work on the history window if it's up. */
- if (historywin != nil) {
- update_history_window(hevt);
- }
- }
- }
-
- void
- update_fire_at_display(Side *side, Unit *unit, Unit *unit2, int m, int rightnow)
- {
- int i, sx1, sy1, sw1, sh1, sx2, sy2, sw2, sh2, dx, dy, xx, yy;
- int startticks, innerticks;
- Map *map;
- GrafPtr oldport, curport = NULL;
-
- if (active_display(side)) {
- GetPort(&oldport);
- startticks = TickCount();
- i = 0;
- /* Tweak the pen modes of all the maps. */
- for_all_maps(map) {
- SetPort(map->window);
- PenMode(patXor);
- if (map->vp->hw > 10) PenSize(2, 2);
- else PenSize(1, 1);
- }
- while (TickCount() < startticks + 32) {
- innerticks = TickCount();
- for_all_maps(map) {
- if (curport != map->window) {
- SetPort(map->window);
- curport = map->window;
- }
- m_xform_unit_self(map, unit, &sx1, &sy1, &sw1, &sh1);
- m_xform_unit_self(map, unit2, &sx2, &sy2, &sw2, &sh2);
- /* Offset to draw lines from the middle of the units' images. */
- sx1 += sw1 / 2; sy1 += sh1 / 2;
- sx2 += sw2 / 2; sy2 += sh2 / 2;
- /* Draw one segment of a line between the units. */
- dx = (sx2 - sx1) / 4; dy = (sy2 - sy1) / 4;
- xx = sx1 + ((i / 2) % 4) * dx; yy = sy1 + ((i / 2) % 4) * dy;
- MoveTo(xx, yy); Line(dx, dy);
- }
- while (TickCount() < innerticks + 1); /* 2 here seems a bit slowish */
- ++i;
- }
- /* Restore the pen modes of all the maps. */
- for_all_maps(map) {
- SetPort(map->window);
- PenNormal();
- }
- SetPort(oldport);
- }
- }
-
- void
- update_fire_into_display(Side *side, Unit *unit, int x2, int y2, int z2, int m, int rightnow)
- {
- int i, sx1, sy1, sw1, sh1, sx2, sy2, sw2, sh2, dx, dy, xx, yy;
- int startticks, innerticks;
- Map *map;
- GrafPtr oldport, curport = NULL;
-
- if (active_display(side)) {
- GetPort(&oldport);
- startticks = TickCount();
- i = 0;
- /* Tweak the pen modes of all the maps. */
- for_all_maps(map) {
- SetPort(map->window);
- PenMode(patXor);
- if (map->vp->hw > 10) PenSize(2, 2);
- else PenSize(1, 1);
- }
- while (TickCount() < startticks + 32) {
- innerticks = TickCount();
- for_all_maps(map) {
- if (curport != map->window) {
- SetPort(map->window);
- curport = map->window;
- }
- m_xform_unit_self(map, unit, &sx1, &sy1, &sw1, &sh1);
- xform(map, x2, y2, &sx2, &sy2);
- sw2 = map->vp->hw; sh2 = map->vp->hh;
- /* Offset to draw lines from the middle of the units' images. */
- sx1 += sw1 / 2; sy1 += sh1 / 2;
- sx2 += sw2 / 2; sy2 += sh2 / 2;
- /* Draw one segment of a line between the units. */
- dx = (sx2 - sx1) / 4; dy = (sy2 - sy1) / 4;
- xx = sx1 + ((i / 2) % 4) * dx; yy = sy1 + ((i / 2) % 4) * dy;
- MoveTo(xx, yy); Line(dx, dy);
- }
- while (TickCount() < innerticks + 1); /* 2 here seems a bit slowish */
- ++i;
- }
- /* Restore the pen modes of all the maps. */
- for_all_maps(map) {
- SetPort(map->window);
- PenNormal();
- }
- SetPort(oldport);
- }
- }
-
- /* Update any displayed info about the given unit. */
-
- void
- update_unit_display(Side *side, Unit *unit, int rightnow)
- {
- UnitCloseup *unitcloseup;
-
- if (active_display(side) && unit != NULL) {
- if (side != unit->side) update_unit_in_maps(unit);
- if (1 /* unit visible to side in any way */ && inside_area(unit->x, unit->y)) {
- update_cell_display(side, unit->x, unit->y, TRUE);
- }
- update_unit_in_lists(unit);
- if ((unitcloseup = find_unit_closeup(unit)) != NULL
- && 1 /* window is visible */) {
- draw_unit_closeup(unitcloseup);
- }
- if (unit->side != NULL && unit->act != NULL) {
- update_side_display(side, unit->side, rightnow);
- }
- if (constructionwin != nil
- && ((WindowPeek) constructionwin)->visible) {
- update_construction_unit_list(unit);
- }
- }
- }
-
- void
- update_unit_acp_display(Side *side, Unit *unit, int rightnow)
- {
- UnitCloseup *unitcloseup;
-
- if (active_display(side) && unit != NULL) {
- #if 0 /* maybe add later, maybe not - acp change not usually visible tho */
- if (side != unit->side) update_unit_in_maps(unit);
- if (1 /* unit visible to side in any way */ && inside_area(unit->x, unit->y)) {
- update_cell_display(side, unit->x, unit->y, TRUE);
- }
- #endif
- update_unit_in_lists(unit);
- unitcloseup = find_unit_closeup(unit);
- if (unitcloseup != NULL && (((WindowPeek) (unitcloseup->window))->visible)) {
- draw_unit_closeup(unitcloseup);
- }
- }
- }
-
- void
- update_unit_in_maps(Unit *unit)
- {
- Map *map;
-
- if (side_controls_unit(dside, unit))
- return;
- for_all_maps(map) {
- unselect_unit_on_map(map, unit);
- }
- }
-
- void
- update_clock_display(Side *side, int rightnow)
- {
- GrafPtr oldport;
- #if 0
- Map *map;
- #endif
- time_t now;
- extern time_t lastnow;
-
- if (active_display(side)) {
- time(&now);
- /* If no changes since the last draw, jump out of here. */
- if (now == lastnow)
- return;
- GetPort(&oldport);
- if (gamewin != nil && ((WindowPeek) gamewin)->visible) {
- SetPort(gamewin);
- draw_game_clocks();
- }
- #if 0 /* no clock display in the topline yet */
- for_all_maps(map) {
- if (map->toph > 0) {
- SetPort(map->window);
- draw_top_line(map);
- }
- }
- #endif
- SetPort(oldport);
- }
- }
-
- void
- update_all_progress_displays(char *str, int s)
- {
- GrafPtr oldport;
- extern char *game_progress_str;
-
- if (!active_display(dside))
- return;
- game_progress_str = str;
- GetPort(&oldport);
- if (gamewin != nil && ((WindowPeek) gamewin)->visible) {
- SetPort(gamewin);
- draw_game_progress();
- }
- SetPort(oldport);
- }
-
- /* Bring up a modal dialog saying that the player has won. */
-
- void
- won_game_dialog()
- {
- int done = FALSE;
- short ditem;
- WindowPtr win;
-
- win = GetNewDialog(dWinGame, NULL, (DialogPtr) -1L);
- ShowWindow(win);
- while (!done) {
- draw_default_button(win, diWinGameQuit);
- SetCursor(&QD(arrow));
- ModalDialog(NULL, &ditem);
- switch (ditem) {
- case diWinGameQuit:
- ExitToShell();
- break;
- case diWinGameContinue:
- done = TRUE;
- break;
- default:
- break;
- }
- }
- DisposDialog(win);
- }
-
- /* Bring up a modal dialog saying that the player has lost. */
-
- void
- lost_game_dialog()
- {
- int done = FALSE;
- short ditem;
- WindowPtr win;
- extern int forcedtoresign;
-
- /* If quitting required a resignation, the player just
- wants out, with no dwelling on final position, so
- bypass the dialog here. */
- if (forcedtoresign) {
- ExitToShell();
- return;
- }
- win = GetNewDialog(dLoseGame, NULL, (DialogPtr) -1L);
- ShowWindow(win);
- while (!done) {
- draw_default_button(win, diLoseGameQuit);
- SetCursor(&QD(arrow));
- ModalDialog(NULL, &ditem);
- switch (ditem) {
- case diLoseGameQuit:
- ExitToShell();
- break;
- case diLoseGameContinue:
- done = TRUE;
- break;
- default:
- break;
- }
- }
- DisposDialog(win);
- }
-
- /* Bring up a modal dialog saying that the game has ended, with no
- implication of the player having either won or lost. */
-
- void
- game_over_dialog()
- {
- int done = FALSE;
- short ditem;
- WindowPtr win;
-
- win = GetNewDialog(dGameOver, NULL, (DialogPtr) -1L);
- ShowWindow(win);
- while (!done) {
- draw_default_button(win, diGameOverQuit);
- SetCursor(&QD(arrow));
- ModalDialog(NULL, &ditem);
- switch (ditem) {
- case diGameOverQuit:
- ExitToShell();
- break;
- case diGameOverContinue:
- done = TRUE;
- break;
- default:
- break;
- }
- }
- DisposDialog(win);
- }
-
- /* Update the displays to reflect the arrival of a message from another
- side. */
-
- void
- update_message_display(Side *side, Side *sender, char *str, int rightnow)
- {
- int done = FALSE;
- short ditem;
- Str255 tmpstr;
- WindowPtr win;
- short itemtype; Handle itemhandle; Rect itemrect;
-
- if (active_display(side)) {
- if (str == NULL)
- str = "";
- if (1 /* chose to make a dialog */) {
- win = GetNewDialog(dMessageReceive, NULL, (DialogPtr) -1L);
- GetDItem(win, diMessageReceiveText, &itemtype, &itemhandle, &itemrect);
- c2p(str, tmpstr);
- SetIText(itemhandle, tmpstr);
- ShowWindow(win);
- while (!done) {
- draw_default_button(win, diMessageReceiveOK);
- SetCursor(&QD(arrow));
- ModalDialog(NULL, &ditem);
- switch (ditem) {
- case diMessageReceiveOK:
- done = TRUE;
- break;
- default:
- break;
- }
- }
- DisposDialog(win);
- } else {
- notify(side, "From %s: %s", side_desig(sender), str);
- }
- }
- }
-
- /* Support for movie display. */
-
- MovieType movie_types[10];
-
- struct a_movie {
- enum movie_type type;
- int args[5];
- };
-
- int numscheduled;
-
- struct a_movie movies[10];
-
- int
- schedule_movie(Side *side, enum movie_type movie, ...)
- {
- int i;
- va_list ap;
-
- if (numscheduled >= 10)
- return FALSE;
- if (side != dside)
- return FALSE;
- memset(&(movies[numscheduled]), 0, sizeof(struct a_movie));
- movies[numscheduled].type = movie;
- va_start(ap, movie);
- for (i = 0; i < 6; ++i)
- movies[numscheduled].args[i] = va_arg(ap, long);
- va_end(ap);
- ++numscheduled;
- return TRUE;
- }
-
- void
- play_movies(SideMask sidemask)
- {
- int i, j;
- int sx, sy, sw, sh;
- int startticks, innerticks;
- Str255 sndnamebuf;
- Map *map;
- Unit *unit;
- GrafPtr oldport, curport = NULL;
- Handle sound;
- extern int numsoundplays;
- long startcount;
-
- if (1 /* anything visible */) {
- GetPort(&oldport);
- startticks = TickCount();
- i = 0;
- /* Tweak the pen modes of all the maps. */
- for_all_maps(map) {
- SetPort(map->window);
- PenMode(patXor);
- if (map->vp->hw > 10) PenSize(2, 2);
- else PenSize(1, 1);
- }
- while (TickCount() < startticks + 32) {
- innerticks = TickCount();
- for (j = 0; j < numscheduled; ++j) {
- if ((movies[j].type == movie_miss
- || movies[j].type == movie_hit
- || movies[j].type == movie_death
- || movies[j].type == movie_extra_0)
- && playsounds
- && numsoundplays < 3) {
-
- if (movies[j].type == movie_extra_0) {
- c2p((char *) movies[j].args[0], sndnamebuf);
- sound = GetNamedResource('snd ', sndnamebuf);
- } else {
- sound = GetNamedResource('snd ', "\pcrunch");
- }
- if (sound != nil) {
- SndPlay(nil, sound, false);
- ReleaseResource(sound);
- }
- ++numsoundplays;
- }
- switch (movies[j].type) {
- case movie_null:
- break;
- case movie_miss:
- unit = (Unit *) movies[j].args[0];
- for_all_maps(map) {
- if (curport != map->window) {
- SetPort(map->window);
- curport = map->window;
- }
- m_xform_unit(map, unit, &sx, &sy, &sw, &sh);
- draw_blast_image(map->window, sx, sy, sw, sh, 0);
- }
- startcount = TickCount();
- /* Delay for part of a second (should relinquish cpu tho) */
- while ((TickCount() - startcount) < 10);
- for_all_maps(map) {
- if (curport != map->window) {
- SetPort(map->window);
- curport = map->window;
- }
- m_xform_unit(map, unit, &sx, &sy, &sw, &sh);
- clear_blast_image(map->window, sx, sy, sw, sh, 2);
- }
- break;
- case movie_hit:
- unit = (Unit *) movies[j].args[0];
- for_all_maps(map) {
- if (curport != map->window) {
- SetPort(map->window);
- curport = map->window;
- }
- m_xform_unit(map, unit, &sx, &sy, &sw, &sh);
- draw_blast_image(map->window, sx, sy, sw, sh, 1);
- }
- startcount = TickCount();
- sound = nil;
- if (playsounds) {
- sound = GetNamedResource('snd ', "\pboom");
- }
- if (sound != nil) {
- SndPlay(nil, sound, false);
- ReleaseResource(sound);
- }
- /* Delay for part of a second (should relinquish cpu tho) */
- while ((TickCount() - startcount) < 10);
- for_all_maps(map) {
- if (curport != map->window) {
- SetPort(map->window);
- curport = map->window;
- }
- m_xform_unit(map, unit, &sx, &sy, &sw, &sh);
- clear_blast_image(map->window, sx, sy, sw, sh, 2);
- }
- break;
- case movie_death:
- unit = (Unit *) movies[j].args[0];
- for_all_maps(map) {
- if (curport != map->window) {
- SetPort(map->window);
- curport = map->window;
- }
- m_xform_unit(map, unit, &sx, &sy, &sw, &sh);
- draw_blast_image(map->window, sx, sy, sw, sh, 2);
- }
- startcount = TickCount();
- sound = nil;
- if (playsounds) {
- sound = GetNamedResource('snd ', "\pboom");
- }
- if (sound != nil) {
- SndPlay(nil, sound, false);
- ReleaseResource(sound);
- }
- /* Delay for part of a second (should relinquish cpu tho) */
- while ((TickCount() - startcount) < 10);
- for_all_maps(map) {
- if (curport != map->window) {
- SetPort(map->window);
- curport = map->window;
- }
- m_xform_unit(map, unit, &sx, &sy, &sw, &sh);
- clear_blast_image(map->window, sx, sy, sw, sh, 2);
- }
- break;
- case movie_nuke:
- break;
- default:
- break;
- }
- }
- while (TickCount() < innerticks + 32);
- ++i;
- }
- /* Restore the pen modes of all the maps. */
- for_all_maps(map) {
- SetPort(map->window);
- PenNormal();
- }
- SetPort(oldport);
- }
- numscheduled = 0;
- }
-
- /* Move the window to a position staggered from the given last position. */
-
- void
- stagger_window(WindowPtr win, int *lasthp, int *lastvp)
- {
- int h, v, retry = 0;
- Rect winrect;
- GrafPtr oldport;
-
- if (*lasthp > 0 && *lastvp > 0) {
- while (1) {
- h = *lasthp + 20; v = *lastvp + 20;
- /* Let windows go partly off the screen, but keep at least the top
- 40x40 pixels visible. */
- if (!position_on_screen(h + 40, v + 40)) {
- if (retry < 20) {
- h = retry * 20; v = 40;
- ++retry;
- } else {
- /* This is getting out of hand - just pick something. */
- h = 20; v = 40;
- break;
- }
- } else if (!position_already_used(h, v)) {
- break;
- }
- }
- MoveWindow(win, h, v, FALSE);
- *lasthp = h; *lastvp = v;
- } else {
- /* Don't move the first window, but do record its position. */
- GetPort(&oldport);
- SetPort(win);
- winrect = win->portRect;
- LocalToGlobal(&top_left(winrect));
- *lasthp = winrect.left; *lastvp = winrect.top;
- SetPort(oldport);
- }
- }
-
- int
- position_on_screen(int h, int v)
- {
- Point pnt;
- GDHandle screen = GetDeviceList();
-
- pnt.h = h; pnt.v = v;
- for (screen = GetDeviceList(); screen != nil; screen = GetNextDevice(screen)) {
- if (TestDeviceAttribute(screen, screenDevice)
- && TestDeviceAttribute(screen, screenActive)) {
- if (PtInRect(pnt, &((*screen)->gdRect)))
- return TRUE;
- }
- }
- return FALSE;
- }
-
- /* (should make this more efficient?) */
-
- int
- position_already_used(int h, int v)
- {
- int i;
- Rect winrect;
- WindowPtr win;
- GrafPtr oldport;
- extern int numwindows;
- extern WindowPtr *winmenuwins;
-
- for (i = 0; i < numwindows; ++i) {
- win = winmenuwins[i];
- GetPort(&oldport);
- SetPort(win);
- winrect = win->portRect;
- LocalToGlobal(&top_left(winrect));
- SetPort(oldport);
- if (h == winrect.left && v == winrect.top)
- return TRUE;
- }
- return FALSE;
- }
-
-
- GDHandle
- best_zoom_screen(Rect *rectptr)
- {
- int greatestarea = 0, sectarea;
- Rect srect;
- GDHandle screen = GetDeviceList(), bestscreen = GetMainDevice();
-
- while (screen != nil) {
- if (TestDeviceAttribute(screen, screenDevice)
- && TestDeviceAttribute(screen, screenActive)) {
- SectRect(rectptr, &((*screen)->gdRect), &srect);
- sectarea = (srect.right - srect.left) * (srect.bottom - srect.top);
- if (sectarea > greatestarea) {
- greatestarea = sectarea;
- bestscreen = screen;
- }
- }
- screen = GetNextDevice(screen);
- }
- return bestscreen;
- }
-
- void
- set_standard_state(WindowPtr win, int fullw, int fullh)
- {
- int screenw, screenh, wintitlehgt, mbaradj = 0;
- Rect winrect, gdrect, zoomrect;
- GDHandle bestscreen;
-
- if (!hasColorQD) {
- zoomrect = QD(screenBits).bounds;
- InsetRect(&zoomrect, 4, 4);
- } else {
- winrect = win->portRect;
- LocalToGlobal((Point *) &(winrect.top));
- LocalToGlobal((Point *) &(winrect.bottom));
- wintitlehgt = winrect.top - 1 - (*(((WindowPeek) win)->strucRgn))->rgnBBox.top;
- /* Get the best screen to zoom on. */
- bestscreen = best_zoom_screen(&winrect);
- gdrect = (*bestscreen)->gdRect;
- /* Adjust to the actual subarea that we can use. */
- if (bestscreen == GetMainDevice()) {
- gdrect.top += GetMBarHeight();
- }
- InsetRect(&gdrect, 3, 3);
- gdrect.top += wintitlehgt;
- screenw = gdrect.right - gdrect.left; screenh = gdrect.bottom - gdrect.top;
- if (winrect.left + fullw <= gdrect.right
- && winrect.top + fullh <= gdrect.bottom) {
- SetRect(&zoomrect, winrect.left, winrect.top, winrect.left + fullw, winrect.top + fullh);
- } else if (fullw <= screenw || fullh <= screenh) {
- SetRect(&zoomrect, gdrect.left, gdrect.top, gdrect.left + fullw, gdrect.top + fullh);
- if (fullw > screenw) zoomrect.right = gdrect.right;
- if (fullh > screenh) zoomrect.bottom = gdrect.bottom;
- } else {
- zoomrect = gdrect;
- }
- }
- ((WStateDataPtr) *(((WindowPeek) win)->dataHandle))->stdState = zoomrect;
- }
-
- /* General routine to outline the given item of a given dialog. */
-
- void
- draw_default_button(DialogPtr dialog, short ditem)
- {
- GrafPtr oldport;
- short itemtype; Handle itemhandle; Rect itemrect;
-
- GetPort(&oldport);
- SetPort(dialog);
- GetDItem(dialog, ditem, &itemtype, &itemhandle, &itemrect);
- PenSize(3, 3);
- InsetRect(&itemrect, -4, -4);
- FrameRoundRect(&itemrect, 16, 16);
- PenNormal();
- SetPort(oldport);
- }
-
- char *
- get_string_from_item(Handle itemhandle)
- {
- char tmpbuf[BUFSIZE];
- Str255 tmpstr;
-
- GetIText(itemhandle, tmpstr);
- p2c(tmpstr, tmpbuf);
- return copy_string(tmpbuf);
- }
-
- /* Cause an update of a window's entire contents. */
-
- void
- force_update(WindowPtr win)
- {
- GrafPtr oldport;
-
- if (win == nil) return;
- GetPort(&oldport);
- SetPort(win);
- EraseRect(&win->portRect);
- InvalRect(&win->portRect);
- SetPort(oldport);
- }
-
- void
- force_overall_update()
- {
- Map *map;
- List *list;
- UnitCloseup *unitcloseup;
-
- force_update(gamewin);
- force_update(historywin);
- force_update(constructionwin);
- force_update(helpwin);
- for_all_maps(map) {
- force_update(map->window);
- }
- for_all_lists(list) {
- force_update(list->window);
- }
- for_all_unit_closeups(unitcloseup) {
- force_update(unitcloseup->window);
- }
- }
-
- void
- beep()
- {
- SysBeep(20);
- }
-
- void
- update_everything()
- {
- if (active_display(dside)) {
- force_overall_update();
- }
- }
-
- /* Set the type and creator of the file to be what is expected
- for a game design. */
-
- void
- set_game_file_type(char *name)
- {
- FileParam pb;
- Str255 tmpstr;
-
- c2p(name, tmpstr);
- pb.ioNamePtr = tmpstr;
- pb.ioVRefNum = 0;
- pb.ioFVersNum = 0;
- pb.ioFDirIndex = 0;
- if (PBGetFInfoSync((ParmBlkPtr) &pb) == noErr) {
- pb.ioFlFndrInfo.fdType = 'TEXT';
- pb.ioFlFndrInfo.fdCreator = XconqSignature;
- PBSetFInfoSync((ParmBlkPtr) &pb);
- }
- }
-